#include <fstream>
#include <string>
#include <iostream>
#include <vector>
using namespace std;

#include "alhelper.h"

asIScriptEngine * AlHelper::sm_pEngine = NULL;

#define MAX_LINE_CHAR 1024

void    AlHelper::InitALScript()
{
    if(NULL == sm_pEngine)
    {
        sm_pEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
        RegisterScriptAny(sm_pEngine);
        RegisterScriptString(sm_pEngine);
        RegisterScriptArray(sm_pEngine, true);
        RegisterScriptMath(sm_pEngine);
        RegisterScriptFile(sm_pEngine);
        RegisterScriptDictionary(sm_pEngine);
    }
}

bool    AlHelper::ComplieScript(const char* aScriptFile)
{
    CScriptBuilder builder;

    int r = builder.StartNewModule(sm_pEngine, aScriptFile);
    if( r < 0 )
    {
        cout << "Failed to start new module" << endl;
        return false;
    }
    r = builder.AddSectionFromFile(aScriptFile);
    if( r < 0 )
    {
        cout << "Failed to add script file" << endl;
        return false;
    }
    r = builder.BuildModule();
    if( r < 0 )
    {
        cout << "Failed to build the module" << endl;
        return false;
    }

    return true;
}
bool    AlHelper::ComplieSimpleScript(const char* aScriptFile)
{
    ifstream fin(aScriptFile);
    string scriptcode;

    char buff[MAX_LINE_CHAR];
    while(fin.good() && !fin.eof())
    {
        fin.getline(buff, sizeof(buff));
        scriptcode += buff;
    }

    asIScriptModule *mod = sm_pEngine->GetModule(aScriptFile, asGM_ALWAYS_CREATE);

    int r = mod->AddScriptSection(aScriptFile, scriptcode.c_str(), scriptcode.length());
    do 
    {
        if (r < 0)
        {
            break;
        }
        r = mod->Build();
        if (r < 0)
        {
            break;
        }

        return true;
    } while (0);

    cout << "Error" << endl;
    cin.get();
    return false;
}

void AlHelper::Callfunction(const char* aModulename, const char* aFuncname)
{
    asIScriptContext *ctx = CreateContext(aModulename, aFuncname);
    if( ctx == 0 )
        return;
    
    ExecuteContext(ctx);
}

bool    AlHelper::RegisterGlobalFunction(const char *aDeclaration, const asSFuncPtr &aFuncPointer, asDWORD aCallConv)
{
    return sm_pEngine->RegisterGlobalFunction(aDeclaration, aFuncPointer, aCallConv) > 0; 
}

bool    AlHelper::RegisterObjectType(const char *aObj, int aByteSize, asDWORD aFlags)
{
    int r = sm_pEngine->RegisterObjectType(aObj, aByteSize, aFlags);
    return r >= 0;
}

bool    AlHelper::RegisterObjectMethod(const char *aObj, const char *aDeclaration, const asSFuncPtr &aFuncPointer, asDWORD aCallConv)
{
    int r = sm_pEngine->RegisterObjectMethod(aObj, aDeclaration, aFuncPointer, aCallConv);
    return r >= 0;
}

bool    AlHelper::RegisterObjectBehaviour(const char *aObj, asEBehaviours aBehaviour, const char *aDeclaration, const asSFuncPtr &aFuncPointer, asDWORD aCallConv)
{
    int r = sm_pEngine->RegisterObjectBehaviour(aObj, aBehaviour, aDeclaration, aFuncPointer, aCallConv);
    return r >= 0;
}

asIScriptContext * AlHelper::CreateContext(const char* aModulename, const char* aFuncname)
{
    asIScriptContext *ctx = NULL;
    int funcID = sm_pEngine->GetModule(aModulename)->GetFunctionIdByDecl(aFuncname);
    if (funcID >= 0)
    {
        ctx = sm_pEngine->CreateContext();
        if (NULL != ctx)
        {
            int r = ctx->Prepare(funcID);
            if( r < 0 )
            {
                ctx->Release();
                ctx = NULL;
            }
        }
    }

    return ctx;
}

void    AlHelper::ExecuteContext(asIScriptContext *ctx)
{
    int r = ctx->Execute();
    if(asEXECUTION_SUSPENDED != r)
    {
        ctx->Abort();
        ctx->Release();
    }
}